Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#if CSVFMTS_ENABLED
-#include "defs.h"
+#include "garmin_txt.h"
-#if CSVFMTS_ENABLED
#include <algorithm> // for for_each, sort
-#include <array> // for array
+#include <array> // for array, array<>::iterator
#include <cctype> // for toupper
#include <cmath> // for fabs, floor
#include <cstdint> // for uint16_t
#include <cstdio> // for sscanf, fprintf, snprintf, stderr
#include <cstdlib> // for abs
#include <cstring> // for strstr, strlen
-#include <ctime> // for time_t, gmtime, localtime, strftime
-#include <optional> // for optional
-#include <utility> // for as_const, pair, make_pair
+#include <ctime> // for gmtime, time_t, localtime, strftime, tm
+#include <optional> // for optional
+#include <type_traits> // for add_const_t
+#include <utility> // for pair, as_const, make_pair
#include <QByteArray> // for QByteArray
#include <QChar> // for QChar, QChar::Other_Control
#include <QDateTime> // for QDateTime
-#include <QIODevice> // for QIODevice, QIODevice::ReadOnly, QIODevice::WriteOnly
+#include <QDebug> // for QDebug
+#include <QIODevice> // for QIODevice, QIODeviceBase::ReadOnly, QIODeviceBase::WriteOnly
#include <QList> // for QList, QList<>::const_iterator
#include <QString> // for QString, operator!=
#include <QStringList> // for QStringList
+#include <QStringLiteral> // for qMakeStringPrivate, QStringLiteral
#include <QTextStream> // for QTextStream
#include <QVector> // for QVector
#include <Qt> // for CaseInsensitive
#include <QtGlobal> // for qRound, qPrintable
+#include "defs.h"
#include "csv_util.h" // for csv_linesplit
#include "formspec.h" // for FormatSpecificDataList
#include "garmin_fs.h" // for garmin_fs_t
#include "garmin_tables.h" // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE...
#include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M
#include "src/core/datetime.h" // for DateTime
-#include "src/core/logging.h" // for Fatal
+#include "src/core/logging.h" // for FatalMsg
#include "src/core/textstream.h" // for TextStream
#define MYNAME "garmin_txt"
-struct gtxt_flags_t {
- unsigned int metric:1;
- unsigned int celsius:1;
- unsigned int utc:1;
- unsigned int enum_waypoints:1;
- unsigned int route_header_written:1;
- unsigned int track_header_written:1;
-};
-
-static gpsbabel::TextStream* fin = nullptr;
-static gpsbabel::TextStream* fout = nullptr;
-static route_head* current_trk;
-static route_head* current_rte;
-static int waypoints;
-static int routepoints;
-static const Waypoint** wpt_a;
-static int wpt_a_ct;
-static grid_type grid_index;
-static int datum_index;
-static const char* datum_str;
-static int current_line;
-static QString date_time_format;
-static int precision = 3;
-static time_t utc_offs = 0;
-static gtxt_flags_t gtxt_flags;
-
-enum header_type {
- waypt_header = 0,
- rtept_header,
- trkpt_header,
- route_header,
- track_header,
- unknown_header
+const QVector<QString> GarminTxtFormat::headers = {
+ "Name\tDescription\tType\tPosition\tAltitude\tDepth\tProximity\tTemperature\t"
+ "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t"
+ "Date Modified\tLink\tCategories",
+ "Waypoint Name\tDistance\tLeg Length\tCourse",
+ "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course",
+ "Name\tLength\tCourse\tWaypoints\tLink",
+ "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink"
};
-inline header_type& operator++(header_type& s) // prefix
-{
- return s = static_cast<header_type>(s + 1);
-}
-inline header_type operator++(header_type& s, int) // postfix
-{
- header_type ret(s);
- ++s;
- return ret;
-}
-
inline gt_display_modes_e& operator++(gt_display_modes_e& s) // prefix
{
return s = static_cast<gt_display_modes_e>(s + 1);
return ret;
}
-static std::array<QList<std::pair<QString, int>>, unknown_header> header_mapping_info;
-static QStringList header_column_names;
-
-static constexpr double kGarminUnknownAlt = 1.0e25;
-static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy";
-static constexpr char kDefaultTimeFormat[] = "HH:mm:ss";
-
-static bool is_valid_alt(double alt)
+bool GarminTxtFormat::is_valid_alt(double alt)
{
return (alt != unknown_alt) && (alt < kGarminUnknownAlt);
}
-static char* opt_datum = nullptr;
-static char* opt_dist = nullptr;
-static char* opt_temp = nullptr;
-static char* opt_date_format = nullptr;
-static char* opt_time_format = nullptr;
-static char* opt_precision = nullptr;
-static char* opt_utc = nullptr;
-static char* opt_grid = nullptr;
-
-static
-QVector<arglist_t> garmin_txt_args = {
- {"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"grid", &opt_grid, "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr},
- {"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
- {"utc", &opt_utc, "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr},
-};
-
-class PathInfo
-{
-public:
- double length {0};
- time_t start {0};
- time_t time {0};
- double speed {0};
- double total {0};
- int count {0};
- const Waypoint* prev_wpt {nullptr};
- const Waypoint* first_wpt {nullptr};
- const Waypoint* last_wpt {nullptr};
-};
-
-static PathInfo* route_info;
-static int route_idx;
-static PathInfo* cur_info;
-
-static const QVector<QString> headers = {
- "Name\tDescription\tType\tPosition\tAltitude\tDepth\tProximity\tTemperature\t"
- "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t"
- "Date Modified\tLink\tCategories",
- "Waypoint Name\tDistance\tLeg Length\tCourse",
- "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course",
- "Name\tLength\tCourse\tWaypoints\tLink",
- "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink"
-};
-
/* helpers */
-static const char*
-get_option_val(const char* option, const char* def)
+const char*
+GarminTxtFormat::get_option_val(const char* option, const char* def)
{
const char* c = (option != nullptr) ? option : def;
return c;
}
-static void
-init_date_and_time_format()
+void
+GarminTxtFormat::init_date_and_time_format()
{
// This is old, and weird, code.. date_time_format is a global that's
// explicitly malloced and freed elsewhere. This isn't very C++ at all,
date_time_format = QStringLiteral("%1 %2").arg(d1, t1);
}
-static void
-convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon)
+void
+GarminTxtFormat::convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) const
{
double alt;
/* Waypoint preparation */
-static void
-enum_waypt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::enum_waypt_cb(const Waypoint* wpt)
{
const garmin_fs_t* gmsd = garmin_fs_t::find(wpt);
int wpt_class = garmin_fs_t::get_wpt_class(gmsd, 0);
/* common route and track pre-work */
-static void
-prework_hdr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::prework_hdr_cb(const route_head* /*unused*/)
{
cur_info = &route_info[route_idx];
}
-static void
-prework_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::prework_tlr_cb(const route_head* /*unused*/)
{
cur_info->last_wpt = cur_info->prev_wpt;
route_idx++;
}
-static void
-prework_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::prework_wpt_cb(const Waypoint* wpt)
{
const Waypoint* prev = cur_info->prev_wpt;
/* output helpers */
-static void
-print_position(const Waypoint* wpt)
+void
+GarminTxtFormat::print_position(const Waypoint* wpt)
{
int valid = 1;
double lat, lon, north, east;
}
}
-static void
-print_date_and_time(const time_t time, const bool time_only)
+void
+GarminTxtFormat::print_date_and_time(const time_t time, const bool time_only)
{
std::tm tm{};
char tbuf[32];
*fout << "\t";
}
-static void
-print_categories(uint16_t categories)
+void
+GarminTxtFormat::print_categories(uint16_t categories)
{
const QStringList categoryList = garmin_fs_t::print_categories(categories);
if (!categoryList.isEmpty()) {
}
}
-static void
-print_course(const Waypoint* A, const Waypoint* B) /* seems to be okay */
+void
+GarminTxtFormat::print_course(const Waypoint* A, const Waypoint* B) /* seems to be okay */
{
if ((A != nullptr) && (B != nullptr) && (A != B)) {
int course = qRound(waypt_course(A, B));
}
}
-static void
-print_distance(const double distance, const bool no_scale, const bool with_tab, const int decis)
+void
+GarminTxtFormat::print_distance(const double distance, const bool no_scale, const bool with_tab, const int decis)
{
double dist = distance;
}
}
-static void
-print_speed(const double distance, const time_t time)
+void
+GarminTxtFormat::print_speed(const double distance, const time_t time)
{
double dist = distance;
const char* unit;
*fout << "\t";
}
-static void
-print_temperature(const float temperature)
+void
+GarminTxtFormat::print_temperature(const float temperature)
{
if (gtxt_flags.celsius) {
*fout << QString::asprintf("%.f C", temperature);
}
}
-static void
-print_string(const char* fmt, const QString& string)
+void
+GarminTxtFormat::print_string(const char* fmt, const QString& string)
{
/* remove unwanted characters from source string */
QString cleanstring;
/* main cb's */
-static void
-write_waypt(const Waypoint* wpt)
+void
+GarminTxtFormat::write_waypt(const Waypoint* wpt)
{
const char* wpt_type;
*fout << "\r\n";
}
-static void
-route_disp_hdr_cb(const route_head* rte)
+void
+GarminTxtFormat::route_disp_hdr_cb(const route_head* rte)
{
cur_info = &route_info[route_idx];
cur_info->prev_wpt = nullptr;
*fout << QStringLiteral("\r\nHeader\t%1\r\n\r\n").arg(headers[rtept_header]);
}
-static void
-route_disp_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::route_disp_tlr_cb(const route_head* /*unused*/)
{
route_idx++;
}
-static void
-route_disp_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::route_disp_wpt_cb(const Waypoint* wpt)
{
const Waypoint* prev = cur_info->prev_wpt;
cur_info->prev_wpt = wpt;
}
-static void
-track_disp_hdr_cb(const route_head* track)
+void
+GarminTxtFormat::track_disp_hdr_cb(const route_head* track)
{
cur_info = &route_info[route_idx];
cur_info->prev_wpt = nullptr;
*fout << QStringLiteral("\r\n\r\nHeader\t%1\r\n\r\n").arg(headers[trkpt_header]);
}
-static void
-track_disp_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::track_disp_tlr_cb(const route_head* /*unused*/)
{
route_idx++;
}
-static void
-track_disp_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::track_disp_wpt_cb(const Waypoint* wpt)
{
const Waypoint* prev = cur_info->prev_wpt;
time_t delta;
* %%% global callbacks called by gpsbabel main process %%% *
*******************************************************************************/
-static void
-garmin_txt_utc_option()
+void
+GarminTxtFormat::garmin_txt_utc_option()
{
if (opt_utc != nullptr) {
if (case_ignore_strcmp(opt_utc, "utc") == 0) {
}
}
-static void
-garmin_txt_adjust_time(QDateTime& dt)
+void
+GarminTxtFormat::garmin_txt_adjust_time(QDateTime& dt) const
{
if (gtxt_flags.utc) {
dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs);
}
}
-static void
-garmin_txt_wr_init(const QString& fname)
+void
+GarminTxtFormat::wr_init(const QString& fname)
{
gtxt_flags = {};
garmin_txt_utc_option();
}
-static void
-garmin_txt_wr_deinit()
+void
+GarminTxtFormat::wr_deinit()
{
fout->close();
delete fout;
date_time_format.squeeze();
}
-static void
-garmin_txt_write()
+void
+GarminTxtFormat::write()
{
+ auto enum_waypt_cb_lambda = [this](const Waypoint* waypointp)->void {
+ enum_waypt_cb(waypointp);
+ };
+ auto prework_hdr_cb_lambda = [this](const route_head* rte)->void {
+ prework_hdr_cb(rte);
+ };
+ auto prework_tlr_cb_lambda = [this](const route_head* rte)->void {
+ prework_tlr_cb(rte);
+ };
+ auto prework_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+ prework_wpt_cb(waypointp);
+ };
+ auto route_disp_hdr_cb_lambda = [this](const route_head* rte)->void {
+ route_disp_hdr_cb(rte);
+ };
+ auto route_disp_tlr_cb_lambda = [this](const route_head* rte)->void {
+ route_disp_tlr_cb(rte);
+ };
+ auto route_disp_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+ route_disp_wpt_cb(waypointp);
+ };
+ auto track_disp_hdr_cb_lambda = [this](const route_head* rte)->void {
+ track_disp_hdr_cb(rte);
+ };
+ auto track_disp_tlr_cb_lambda = [this](const route_head* rte)->void {
+ track_disp_tlr_cb(rte);
+ };
+ auto track_disp_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+ track_disp_wpt_cb(waypointp);
+ };
+
QString grid_str = gt_get_mps_grid_longname(grid_index, MYNAME);
grid_str = grid_str.replace('*', "°");
*fout << "Grid\t" << grid_str << "\r\n";
waypoints = 0;
gtxt_flags.enum_waypoints = 1; /* enum all waypoints */
- waypt_disp_all(enum_waypt_cb);
- route_disp_all(nullptr, nullptr, enum_waypt_cb);
+ waypt_disp_all(enum_waypt_cb_lambda);
+ route_disp_all(nullptr, nullptr, enum_waypt_cb_lambda);
gtxt_flags.enum_waypoints = 0;
if (waypoints > 0) {
wpt_a_ct = 0;
wpt_a = new const Waypoint*[waypoints] {};
- waypt_disp_all(enum_waypt_cb);
- route_disp_all(nullptr, nullptr, enum_waypt_cb);
+ waypt_disp_all(enum_waypt_cb_lambda);
+ route_disp_all(nullptr, nullptr, enum_waypt_cb_lambda);
auto sort_waypt_lambda = [](const Waypoint* wa, const Waypoint* wb)->bool {
return wa->shortname.compare(wb->shortname, Qt::CaseInsensitive) < 0;
};
route_idx = 0;
route_info = new PathInfo[route_count()];
routepoints = 0;
- route_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
+ route_disp_all(prework_hdr_cb_lambda, prework_tlr_cb_lambda, prework_wpt_cb_lambda);
+
if (routepoints > 0) {
route_idx = 0;
- route_disp_all(route_disp_hdr_cb, route_disp_tlr_cb, route_disp_wpt_cb);
+ route_disp_all(route_disp_hdr_cb_lambda, route_disp_tlr_cb_lambda, route_disp_wpt_cb_lambda);
}
delete[] route_info;
route_info = nullptr;
route_idx = 0;
route_info = new PathInfo[track_count()];
routepoints = 0;
- track_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
+ track_disp_all(prework_hdr_cb_lambda, prework_tlr_cb_lambda, prework_wpt_cb_lambda);
if (routepoints > 0) {
route_idx = 0;
- track_disp_all(track_disp_hdr_cb, track_disp_tlr_cb, track_disp_wpt_cb);
+ track_disp_all(track_disp_hdr_cb_lambda, track_disp_tlr_cb_lambda, track_disp_wpt_cb_lambda);
}
delete[] route_info;
}
/* helpers */
-static void
-free_headers()
+void
+GarminTxtFormat::free_headers()
{
std::for_each(header_mapping_info.begin(), header_mapping_info.end(),
[](auto& list)->void { list.clear(); });
// Super simple attempt to convert strftime/strptime spec to Qt spec.
// This misses a LOT of cases and vagaries, but the reality is that we
// see very few date formats here.
-static QString
-strftime_to_timespec(const char* s)
+QString
+GarminTxtFormat::strftime_to_timespec(const char* s)
{
QString q;
int l = strlen(s);
/* data parsers */
-static QDateTime
-parse_date_and_time(const QString& str)
+QDateTime
+GarminTxtFormat::parse_date_and_time(const QString& str)
{
QString timespec = strftime_to_timespec(CSTR(date_time_format));
return QDateTime::fromString(QString(str).trimmed(), timespec);
}
-static uint16_t
-parse_categories(const QString& str)
+uint16_t
+GarminTxtFormat::parse_categories(const QString& str) const
{
uint16_t res = 0;
return res;
}
-static bool
-parse_temperature(const QString& str, double* temperature)
+bool
+GarminTxtFormat::parse_temperature(const QString& str, double* temperature) const
{
double value;
unsigned char unit;
return false;
}
-static void
-parse_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_header(const QStringList& lineparts)
{
header_column_names.clear();
for (const auto& name : lineparts) {
}
}
-static bool
-parse_display(const QString& str, int* val)
+bool
+GarminTxtFormat::parse_display(const QString& str, int* val) const
{
if (str.isEmpty()) {
return false;
return false;
}
-static void
-bind_fields(const header_type ht)
+void
+GarminTxtFormat::bind_fields(const header_type ht)
{
if ((grid_index < 0) || (datum_index < 0)) {
fatal(MYNAME ": Incomplete or invalid file header!");
header_column_names.clear();
}
-static void
-parse_grid(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_grid(const QStringList& lineparts)
{
if (lineparts.empty()) {
fatal(MYNAME ": Missing grid headline!\n");
}
}
-static void
-parse_datum(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_datum(const QStringList& lineparts)
{
if (lineparts.empty()) {
fatal(MYNAME ": Missing GPS datum headline!\n");
datum_index = gt_lookup_datum_index(CSTR(str), MYNAME);
}
-static void
-parse_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_waypoint(const QStringList& lineparts)
{
int column = -1;
waypt_add(wpt);
}
-static void
-parse_route_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_route_header(const QStringList& lineparts)
{
int column = -1;
current_rte = rte;
}
-static void
-parse_track_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_track_header(const QStringList& lineparts)
{
int column = -1;
}
-static void
-parse_route_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_route_waypoint(const QStringList& lineparts)
{
int column = -1;
Waypoint* wpt = nullptr;
}
}
-static void
-parse_track_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_track_waypoint(const QStringList& lineparts)
{
int column = -1;
/***************************************************************/
-static void
-garmin_txt_rd_init(const QString& fname)
+void
+GarminTxtFormat::rd_init(const QString& fname)
{
gtxt_flags = {};
garmin_txt_utc_option();
}
-static void
-garmin_txt_rd_deinit()
+void
+GarminTxtFormat::rd_deinit()
{
free_headers();
header_column_names.clear();
date_time_format.squeeze();
}
-static void
-garmin_txt_read()
+void
+GarminTxtFormat::read()
{
QString buff;
}
}
-
-/*
- * The file encoding is windows-1252.
- * Conversion between windows-1252 and utf-16 is handled by the stream.
- * Conversion between utf-16 and utf-8 is handled by this format.
- * Let main know char strings have already been converted to utf-8
- * so it doesn't attempt to re-convert any char strings including gmsd data.
- */
-
-ff_vecs_t garmin_txt_vecs = {
- ff_type_file,
- FF_CAP_RW_ALL,
- garmin_txt_rd_init,
- garmin_txt_wr_init,
- garmin_txt_rd_deinit,
- garmin_txt_wr_deinit,
- garmin_txt_read,
- garmin_txt_write,
- nullptr,
- &garmin_txt_args,
- NULL_POS_OPS
-};
-
#endif // CSVFMTS_ENABLED
--- /dev/null
+/*
+
+ Support for MapSource Text Export (Tab delimited) files.
+
+ Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org
+ Copyright (C) 2004-2022 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ */
+#ifndef GARMIN_TXT_H_INCLUDED_
+#define GARMIN_TXT_H_INCLUDED_
+
+#if CSVFMTS_ENABLED
+
+#include <array> // for array
+#include <cstdint> // for uint16_t
+#include <ctime> // for time_t
+#include <utility> // for pair
+
+#include <QDateTime> // for QDateTime
+#include <QList> // for QList
+#include <QString> // for QString
+#include <QStringList> // for QStringList
+#include <QVector> // for QVector
+
+#include "defs.h"
+#include "format.h" // for Format
+#include "src/core/textstream.h" // for TextStream
+
+
+class GarminTxtFormat : public Format
+{
+public:
+ QVector<arglist_t>* get_args() override
+ {
+ return &garmin_txt_args;
+ }
+
+ ff_type get_type() const override
+ {
+ return ff_type_file;
+ }
+
+ QVector<ff_cap> get_cap() const override
+ {
+ return FF_CAP_RW_ALL;
+ }
+
+ void rd_init(const QString& fname) override;
+ void read() override;
+ void rd_deinit() override;
+ void wr_init(const QString& fname) override;
+ void write() override;
+ void wr_deinit() override;
+
+private:
+ /* Constants */
+
+ static constexpr double kGarminUnknownAlt = 1.0e25;
+ static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy";
+ static constexpr char kDefaultTimeFormat[] = "HH:mm:ss";
+
+ static const QVector<QString> headers;
+
+ /* Types */
+
+ struct gtxt_flags_t {
+ unsigned int metric:1;
+ unsigned int celsius:1;
+ unsigned int utc:1;
+ unsigned int enum_waypoints:1;
+ unsigned int route_header_written:1;
+ unsigned int track_header_written:1;
+ };
+
+ enum header_type {
+ waypt_header = 0,
+ rtept_header,
+ trkpt_header,
+ route_header,
+ track_header,
+ unknown_header
+ };
+
+ class PathInfo
+ {
+ public:
+ double length {0};
+ time_t start {0};
+ time_t time {0};
+ double speed {0};
+ double total {0};
+ int count {0};
+ const Waypoint* prev_wpt {nullptr};
+ const Waypoint* first_wpt {nullptr};
+ const Waypoint* last_wpt {nullptr};
+ };
+
+ /* Member Functions */
+
+ static bool is_valid_alt(double alt);
+ static const char* get_option_val(const char* option, const char* def);
+ void init_date_and_time_format();
+ void convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) const;
+ void enum_waypt_cb(const Waypoint* wpt);
+ void prework_hdr_cb(const route_head* unused);
+ void prework_tlr_cb(const route_head* unused);
+ void prework_wpt_cb(const Waypoint* wpt);
+ void print_position(const Waypoint* wpt);
+ void print_date_and_time(time_t time, bool time_only);
+ void print_categories(uint16_t categories);
+ void print_course(const Waypoint* A, const Waypoint* B);
+ void print_distance(double distance, bool no_scale, bool with_tab, int decis);
+ void print_speed(double distance, time_t time);
+ void print_temperature(float temperature);
+ void print_string(const char* fmt, const QString& string);
+ void write_waypt(const Waypoint* wpt);
+ void route_disp_hdr_cb(const route_head* rte);
+ void route_disp_tlr_cb(const route_head* unused);
+ void route_disp_wpt_cb(const Waypoint* wpt);
+ void track_disp_hdr_cb(const route_head* track);
+ void track_disp_tlr_cb(const route_head* unused);
+ void track_disp_wpt_cb(const Waypoint* wpt);
+ void garmin_txt_utc_option();
+ void garmin_txt_adjust_time(QDateTime& dt) const;
+ void free_headers();
+ static QString strftime_to_timespec(const char* s);
+ QDateTime parse_date_and_time(const QString& str);
+ uint16_t parse_categories(const QString& str) const;
+ bool parse_temperature(const QString& str, double* temperature) const;
+ void parse_header(const QStringList& lineparts);
+ bool parse_display(const QString& str, int* val) const;
+ void bind_fields(header_type ht);
+ void parse_grid(const QStringList& lineparts);
+ void parse_datum(const QStringList& lineparts);
+ void parse_waypoint(const QStringList& lineparts);
+ void parse_route_header(const QStringList& lineparts);
+ void parse_track_header(const QStringList& lineparts);
+ void parse_route_waypoint(const QStringList& lineparts);
+ void parse_track_waypoint(const QStringList& lineparts);
+
+ /* Data Members */
+
+ gpsbabel::TextStream* fin = nullptr;
+ gpsbabel::TextStream* fout = nullptr;
+ route_head* current_trk{};
+ route_head* current_rte{};
+ int waypoints{};
+ int routepoints{};
+ const Waypoint** wpt_a{};
+ int wpt_a_ct{};
+ grid_type grid_index{};
+ int datum_index{};
+ const char* datum_str{};
+ int current_line{};
+ QString date_time_format;
+ int precision = 3;
+ time_t utc_offs = 0;
+ gtxt_flags_t gtxt_flags{};
+
+ std::array<QList<std::pair<QString, int>>, unknown_header> header_mapping_info;
+ QStringList header_column_names;
+
+ char* opt_datum = nullptr;
+ char* opt_dist = nullptr;
+ char* opt_temp = nullptr;
+ char* opt_date_format = nullptr;
+ char* opt_time_format = nullptr;
+ char* opt_precision = nullptr;
+ char* opt_utc = nullptr;
+ char* opt_grid = nullptr;
+
+ QVector<arglist_t> garmin_txt_args = {
+ {"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"grid", &opt_grid, "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr},
+ {"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+ {"utc", &opt_utc, "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr},
+ };
+
+ PathInfo* route_info{};
+ int route_idx{};
+ PathInfo* cur_info{};
+};
+
+#endif // CSVFMTS_ENABLED
+#endif // GARMIN_TXT_H_INCLUDED_